#ifndef IBASEDATALINK_H_
#define IBASEDATALINK_H_

#pragma warning(disable:4251)
#include <cstdint>
#include <memory>

#include "zlbase/global.h"

namespace zl
{
namespace zlbase
{
/// \brief 数据链路类型
enum EDatalinkType
{
    EDatalinkType_EthernetUdp = ZLBASE_DATALINK(1000),  ///< 以太网口UDP
    EDatalinkType_EthernetTcp = ZLBASE_DATALINK(2000),  ///< 以太网口TCP
    EDatalinkType_Serialport = ZLBASE_DATALINK(3000)    ///< 串口
};

/// \brief 数据链路配置项
///
/// 包含了网口配置选项和串口配置选项，使用的时候根据type来指定要创建的链路类型
struct ZLBASE_API DatalinkOption
{
    int32_t type = EDatalinkType_EthernetUdp;  ///< 链路类型，根据 EDatalinkType指定
    bool is_shared = false;                    ///< 是否为共享链路

    // 网口配置项
    char localaddr[256];   ///< 本地地址
    int32_t localport;     ///< 本地端口
    char remoteaddr[256];  ///< 远程地址
    int32_t remoteport;    ///< 远程端口

    // 串口配置项
    char com[256];           ///< 设备串口名
    int32_t baud_rate;       ///< 串口波特率（默认 9600）
    int32_t flow_control;    ///< 串口流控 （默认 无）(none: 0, software: 1, hardware: 2)
    int32_t parity;          ///< 串口校验位 （默认 无）(none: 0, odd: 1, even: 2)
    int32_t stop_bits;       ///< 串口停止位 （默认 0）(one: 0, onepointfive: 1, two: 2)
    int32_t character_size;  ///< 串口数据位 （默认 8）(5, 6, 7, 8)

    DatalinkOption();
    DatalinkOption(const DatalinkOption &other);
    DatalinkOption &operator=(const DatalinkOption &other);
};

/// \brief 数据链路读写回调函数
///
/// 当链路中有数据读写时会调用该回调函数，用于应用层监视底层链路的数据读写情况
/// \param[in] type 读写类型（0：写，1：读）
/// \param[in] origin 链路的标识信息
/// \param[in] buff 数据
/// \param[in] buff_len 数据长度
typedef void (*Handler)(int type, const char *origin, const unsigned char *buff, size_t buff_len);

/// \brief 数据链路层接口类
class ZLBASE_API IBaseDatalink
{
public:
    IBaseDatalink();
    virtual ~IBaseDatalink();

    /// \brief 设置读写回调接口
    virtual void SetHandler(Handler handler);

    /// \brief 设置链路选项
    virtual void SetOption(const DatalinkOption &option) = 0;

    /// \brief 获取链路选项
    virtual DatalinkOption GetOption() = 0;

    /// \brief 锁定链路对象
    ///
    /// 获取一个该链路的所有权防止出现多个线程同时读写某一个链路的情况
    /// \param[in] flag true: 获取，false: 释放
    /// \return 获取所有权是否成功
    virtual void AcquireOwnership(bool flag) = 0;

    /// \brief 链路是否打开
    virtual bool IsOpen() = 0;

    /// \brief 打开链路
    virtual int32_t Open() = 0;

    /// \brief 关闭链路
    virtual int32_t Close() = 0;

    /// \brief 从链路中读取数据
    ///
    /// \param[in] buf 用来缓存数据的缓冲区
    /// \param[in] len 缓冲区的长度
    /// \return 实际读取的数据长度
    virtual int32_t Read(unsigned char *buff, size_t len) = 0;

    /// \brief 从链路中读取数据
    ///
    /// \param[in] buf 用来缓存数据的缓冲区
    /// \param[in] len 缓冲区的长度
    /// \param[in] timeout 操作的超时时间（单位毫秒）
    /// \return 实际读取的数据长度
    virtual int32_t Read(unsigned char *buff, size_t len, int32_t timeout) = 0;

    /// \brief 从链路中读取指定字节数
    ///
    /// 尝试从链路中读取指定数量的字节，并返回实际读取的字节数
    /// \param[in] 用来缓存数据的缓冲区
    /// \param[in] len　缓冲区长度
    /// \param[in] count　需要读取的字节数
    /// \param[in] timeout 操作超时时间（单位毫秒）
    /// \return
    virtual int32_t Read(unsigned char *buff, size_t len, size_t count, int32_t timeout) = 0;

    /// \brief 写入数据到链路中
    ///
    /// \param[in] buf 写入数据的指针
    /// \param[in] len 要写入数据的长度
    /// \param[in] timeout 操作的超时时间（单位毫秒）
    /// \return 实际写入的数据长度
    virtual int32_t Write(const unsigned char *buff, size_t len) = 0;

    /// \brief 写入数据到链路中
    ///
    /// \param[in] buf 写入数据的指针
    /// \param[in] len 要写入数据的长度
    /// \param[in] timeout 操作的超时时间（单位毫秒）
    /// \return 实际写入的数据长度
    virtual int32_t Write(const unsigned char *buff, size_t len, int32_t timeout) = 0;
};

/// \brief 自动锁定解锁链路对象
class ZLBASE_API CAutoDatalinkLocker
{
public:
    CAutoDatalinkLocker(std::shared_ptr<IBaseDatalink> ptr) :
        ptr_(ptr)
    {
        ptr_->AcquireOwnership(true);
    }
    ~CAutoDatalinkLocker()
    {
        ptr_->AcquireOwnership(false);
    }

private:
    std::shared_ptr<IBaseDatalink> ptr_;
};

}  // namespace zlbase
}  // namespace zl

#endif  // IBASEDATALINK_H_
